﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Core
{
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UITile<T> : UIWidget, IUITile
        where T : UITileElement
    {
        private readonly List<T> elements = new();

        public int Count => elements.Count;

        private Action<T, int> updateFunc;
        private Action<T, int> selectFunc;
        private Action<string, T, int> eventFunc;

        public void SetUpdateFunc(Action<T, int> func) => updateFunc = func;
        public void SetSelectFunc(Action<T, int> func) => selectFunc = func;
        public void SetEventFunc(Action<string, T, int> func) => eventFunc = func;

        public void Foreach(Action<T, int> func)
        {
            if (func == null) return;

            for (int i = 0; i < Count; i++)
            {
                func(elements[i], i);
            }
        }

        public void Foreach(int[] indexArr, Action<T, int> func)
        {
            if (func == null) return;

            for (int i = 0; i < indexArr.Length; i++)
            {
                var index = indexArr[i];
                func(elements[index], index);
            }
        }

        private Transform oriItem;

        public override void Awake(GameObject go)
        {
            base.Awake(go);

            oriItem = transform.GetChild(0);

            for (int i = 0; i < transform.childCount; i++)
            {
                var child = transform.GetChild(i).gameObject;
                var t = G.Factory.Create<T, IUITile, GameObject>(this, child);
                t.Init();
                elements.Add(t);
                UIEventListener.Get(t.gameObject).OnClick += OnItemClickHandler;
            }
        }

        public override void Dispose()
        {
            if (IsDisposed) return;
            base.Dispose();

            updateFunc = null;
            selectFunc = null;

            for (int i = 0; i < elements.Count; i++)
            {
                var t = elements[i];
                UIEventListener.Get(t.gameObject).OnClick -= OnItemClickHandler;
                t.Dispose();
            }
            elements.Clear();

        }

        public T GetChildAt(int index)
        {
            if (index < 0 || index >= elements.Count)
            {
                return null;
            }
            return elements[index];
        }

        public void SetAmount(int count)
        {
            if (elements.Count < count)
            {
                var cnt = elements.Count;
                for (int i = cnt; i < count; i++)
                {
                    Transform child = null;

                    if (transform.childCount > i)
                    {
                        child = transform.GetChild(i);
                    }

                    child = child != null ? child : GameObject.Instantiate(oriItem);

                    child.SetParent(transform);
                    child.Reset();

                    var t = G.Factory.Create<T, IUITile, GameObject>(this, transform.GetChild(i).gameObject);
                    t.Init();
                    elements.Add(t);

                    UIEventListener.Get(t.gameObject).OnClick += OnItemClickHandler;
                }
            }

            for (int i = 0; i < elements.Count; i++)
            {
                if (i < count)
                {
                    elements[i].SetActive(true);
                    updateFunc?.Invoke(elements[i], i);
                }
                else
                {
                    elements[i].SetActive(false);
                }
            }

        }

        public void Refresh()
        {
            for (int i = 0; i < elements.Count; i++)
            {
                updateFunc?.Invoke(elements[i], i);
            }
        }

        public void SetSelect(int index)
        {
            if (index < 0 || index >= Count)
            {
                index = 0;
            }

            var item = elements[index];
            selectFunc?.Invoke(item, index);
        }

        public void OnFirstClick()
        {
            var first = GetChildAt(0);
            if (first != null)
            {
                OnItemClickHandler(first.gameObject);
            }
        }

        private void OnItemClickHandler(GameObject arg1)
        {
            T item = default;
            for (int i = 0; i < elements.Count; i++)
            {
                var c = elements[i];
                if (c.gameObject == arg1)
                {
                    item = c;
                    break;
                }
            }
            var index = elements.IndexOf(item);
            selectFunc?.Invoke(item, index);
        }

        public void Dispatch(string key, UITileElement element)
        {
            if (element is not T t)
            {
                return;
            }
            var index = elements.IndexOf(t);
            eventFunc?.Invoke(key, t, index);
        }
    }
}
